package cn.itedus.lottery.domain.strategy.service.algorithm.impl;

import cn.itedus.lottery.domain.strategy.model.vo.AwardRateVO;
import cn.itedus.lottery.domain.strategy.service.algorithm.BaseAlgorithm;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 必中奖策略抽奖，排掉已经空了的概率，重新计算中奖范围
 */
@Component("entiretyRateRandomDrawAlgorithm")  //不指定name也行，默认 Bean 名称为类名首字母小写
public class EntiretyRateRandomDrawAlgorithm extends BaseAlgorithm {
    /**
     * 先排除已经空的奖品，SecureRandom 生成随机数，索引到对应的奖品信息返回结果
     *  *在initRateTuple中初始化了rateTupleMap字典（strategyId -> rateTuple）和awardRateInfoMap字典（strategyId -> [awardId->begin、awardId->end]）
     *  * 比如策略id为1,这个策略要求一等奖概率0.2,二等奖概率0.3,三等奖概率0.5 放入和awardRateInfoMap字典
     *  * 概率散列这个列表包含128个元素,其中有20个存储一等奖的奖品id,30个存储二等奖的奖品id,50个存储三等奖的奖品id,放入rateTupleMap字典
     *
     * @param strategyId 策略ID
     * @param excludeAwardIds 排除掉已经不能作为抽奖的奖品ID，留给风控和空库存使用
     * @return
     */
    @Override
    public String randomDraw(Long strategyId, List<String> excludeAwardIds) {
        BigDecimal differenceDenominator = BigDecimal.ZERO;

        // 排除掉不在抽奖范围的奖品ID集合
        List<AwardRateVO> differenceAwardRateList = new ArrayList<>();
        List<AwardRateVO> awardRateIntervalValList = awardRateInfoMap.get(strategyId);
        for (AwardRateVO awardRateVO : awardRateIntervalValList) {
            String awardId = awardRateVO.getAwardId();
            if (excludeAwardIds.contains(awardId)) {
                continue;
            }
            differenceAwardRateList.add(awardRateVO);
            differenceDenominator = differenceDenominator.add(awardRateVO.getAwardRate());  //比如一等奖抽完了，可能就是0.3+0.5
        }

        // 前置判断 如果没有奖品了，返回null
        if (differenceAwardRateList.size() == 0) {
            return null;
        }
        // 前置判断 如果只有一种奖品，直接返回
        if (differenceAwardRateList.size() == 1) {
            return differenceAwardRateList.get(0).getAwardId();
        }

        // 获取随机概率值
        int randomVal = this.generateSecureRandomIntCode(100);

        // 循环获取奖品 根据随机数依次比对奖品概率区间，找到对应的奖品id
        String awardId = null;
        int cursorVal = 0;
        for (AwardRateVO awardRateVO : differenceAwardRateList) {
            //BigDecimal的divide(BigDecimal,scale,roundingMode)，scale表示保留几位小数（2），roundingMode表示取舍模式（向上取整）
            //以二等奖概率0.3为例，0.3/0.8=0.375向上取整为0.38再乘100 = 38
            int rateVal = awardRateVO.getAwardRate().divide(differenceDenominator, 2, BigDecimal.ROUND_UP).multiply(new BigDecimal(100)).intValue();
            //判断随机数是否小于38，是的话就在二等奖区间，直接返回二等奖的奖品id。不是的话进入下个循环，判断是否小于101...
            if (randomVal <= (cursorVal + rateVal)) {
                awardId = awardRateVO.getAwardId();
                break;
            }
            cursorVal += rateVal;
        }

        // 返回中奖结果
        return awardId;
    }
}
